package bb.lanxing.service;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;

import androidx.core.app.NotificationCompat;

import bb.lanxing.App;
import bb.lanxing.R;
import bb.lanxing.activity.launch.LaunchActivity;
import bb.lanxing.activity.sport.SportActivity;
import bb.lanxing.calc.data.DisplayPoint;
import bb.lanxing.calc.data.SourcePoint;
import bb.lanxing.calc.processer.ProcessorFactory;
import bb.lanxing.calc.processer.i.IWorkoutProcessor;
import bb.lanxing.common.config.Constants;
import bb.lanxing.common.engin.util.LocationRecorder;
import bb.lanxing.common.engin.util.LocationSimulator;
import bb.lanxing.devices.utils.XZDeviceHelper;
import bb.lanxing.lib.devices.api.DeviceManager;
import bb.lanxing.lib.devices.base.DeviceContext;
import bb.lanxing.lib.devices.base.XZDeviceManager;
import bb.lanxing.manager.ISPChangedListener;
import bb.lanxing.manager.RemoteSharedPreference;
import bb.lanxing.manager.SPConstant;
import bb.lanxing.manager.SharedManager;
import bb.lanxing.manager.SourcePointManager;
import bb.lanxing.model.WorkoutDatabaseHelper;
import bb.lanxing.model.database.Workout;
import bb.lanxing.util.AppFileUtils;
import bb.lanxing.util.Log;
import bb.lanxing.util.NotificationConstants;

/**
 * 开始运动后刷新各项数据的service
 */
public class WorkoutRemoteService extends Service {
    private static final String TAG = "WorkoutRemoteService";
    // 数据刷新时间间隔
    private static final long TIME_INTERVAL = 1000L;

    // 开始运动后刷新各项数据的定时器
    private Timer workoutTimer;
    // 计算各种运动数据的干活的
    private IWorkoutProcessor biciSimpleWorkoutProcessor;
    private IWorkoutProcessor recordWorkoutProcessor;
    private IWorkoutProcessor simpleWorkoutProcessor;
    // 运动数据的载体
    private DisplayPoint displayPoint;
    // 运动类型，有问题
    private int[] dataTypes = RemoteSharedPreference.getInstance().getSportTypes();
    // 保持长唤醒
    private PowerManager.WakeLock wakeLock;
    // 后台任务Id
    private int daemonJobId = 1;
    // 上次daemon时间？
    private long lastDaemonTime = 0;
    // service是否已运行
    private boolean isServiceRunning = false;
    // 是否已开始运动
    private boolean isSporting = false;

    private final ISPChangedListener spChangedListener = new ISPChangedListener() {
        @Override
        public void onParamChanged(String str, Object obj) {
            if (SPConstant.KEY_PEBBLE_WATCH.equals(str) || SPConstant.KEY_ANDROID_WEAR.equals(str)
                    || SPConstant.KEY_TENCENT_WATCH.equals(str) || SPConstant.KEY_MAIBU_WATCH.equals(str)) {
                return;
            }
            if (SPConstant.KEY_TTS_SOUND_ENABLE.equals(str) || SPConstant.KEY_GPS_SOUND_ENABLED.equals(str)
                    || SPConstant.KEY_TTS_DISTANCE.equals(str) || SPConstant.KEY_TTS_DURATION.equals(str)
                    || SPConstant.KEY_TTS_SPEED_WARNING_ENABLE.equals(str)
                    || SPConstant.KEY_TTS_SPEED_WARNING_VALUE.equals(str)
                    || SPConstant.KEY_ALTITUDE_SOURCE_V2.equals(str)
                    || SPConstant.KEY_ALTITUDE_ADJUST_VALUE_V2.equals(str)) {
                if (recordWorkoutProcessor != null) {
                    recordWorkoutProcessor.updateConfigs(str, obj);
                }
            } else if (SPConstant.KEY_SPORT_DATA_TYPES.equals(str)) {
                dataTypes = RemoteSharedPreference.getInstance().getSportTypes();
                if (simpleWorkoutProcessor != null) {
                    simpleWorkoutProcessor = ProcessorFactory.create(ProcessorFactory.TYPE_SIMPLE);
                    simpleWorkoutProcessor.init(dataTypes);
                }
            } else if (SPConstant.KEY_TTS_HEART_WARNING_ENABLE.equals(str)) {
                DeviceManager deviceManager = DeviceContext.getDeviceManager();
                if (deviceManager instanceof XZDeviceManager) {
                    ((XZDeviceManager) deviceManager).onConfigHeartRate((Boolean) obj,
                            RemoteSharedPreference.getInstance().getHeartRateWarningValue());
                }
            } else if (SPConstant.KEY_TTS_HEART_WARNING_VALUE.equals(str)) {
                DeviceManager deviceManager2 = DeviceContext.getDeviceManager();
                if (deviceManager2 instanceof XZDeviceManager) {
                    ((XZDeviceManager) deviceManager2).onConfigHeartRate(
                            RemoteSharedPreference.getInstance()
                                    .getBoolean(SPConstant.KEY_TTS_HEART_WARNING_ENABLE, false),
                            Integer.parseInt(obj.toString()));
                }
            }
        }
    };

    private IWorkoutRemoteService.Stub mBinder = new IWorkoutRemoteService.Stub() {
        @Override
        public void startSport(long workoutId) {
        }

        @Override
        public boolean isServiceRunning() {
            return isServiceRunning;
        }

        @Override
        public DisplayPoint getDisplayPoint() {
            Log.v(TAG, "getDisplayPoint, isSporting = " + isSporting);
            if (!isSporting) {
                if (simpleWorkoutProcessor == null) {
                    simpleWorkoutProcessor = ProcessorFactory.create(ProcessorFactory.TYPE_SIMPLE);
                    if (simpleWorkoutProcessor != null) {
                        simpleWorkoutProcessor.init(dataTypes);
                    }
                }
                SourcePoint sourcePoint = SourcePointManager.getInstance().getSourcePoint();
                Log.v(TAG, "getDisplayPoint, simpleWorkoutProcessor.process...");
                displayPoint = simpleWorkoutProcessor.process(sourcePoint);
            }
            return displayPoint;
        }

        @Override
        public DisplayPoint getBiciDisplayPoint() {
            if (biciSimpleWorkoutProcessor == null) {
                biciSimpleWorkoutProcessor = ProcessorFactory.create(ProcessorFactory.TYPE_BICI_SIMPLE);
				biciSimpleWorkoutProcessor.init();
			}
            SourcePoint biciSourcePoint = SourcePointManager.getInstance().getBiciSourcePoint();
            Log.v(TAG, "getBiciDisplayPoint, biciSimpleWorkoutProcessor.process...");
            displayPoint = biciSimpleWorkoutProcessor.process(biciSourcePoint);
            return displayPoint;
        }

        @Override
        public void flushLocation() {
            if (recordWorkoutProcessor != null) {
                recordWorkoutProcessor.flushPoint(false);
            }
        }

        @Override
        public void stopSport() {
            WorkoutRemoteService.this.stopSport();
        }

        @Override
        public boolean isSporting() {
            return isSporting;
        }

        @Override
        public void openBLE() {
            WorkoutRemoteService.this.openBLE();
        }

        @Override
        public void closeBLE() {
            Intent intent = new Intent(DeviceService.ACTION_CLOSE_BLE);
            intent.setPackage(getPackageName());
            startService(intent);
        }

        @Override
        public void pauseSportByUser(boolean pause) {
            if (recordWorkoutProcessor != null) {
                recordWorkoutProcessor.pauseSportByUser(pause);
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate ======= ");
        isServiceRunning = true;
        RemoteSharedPreference.getInstance().registerSPChangedListener(spChangedListener);
        displayPoint = new DisplayPoint();
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind ======= ");
        return mBinder;
    }

    @Override
    public int onStartCommand(Intent intent, int i, int i2) {
        Log.logd(TAG, "onStartCommand ======= " + intent + ", flags = " + i + ", startId = " + i2);
        showNotification();
        if (!isSporting && intent != null) {
            boolean booleanExtra = intent.getBooleanExtra("daemon", false);
            boolean booleanExtra2 = intent.getBooleanExtra("record_open", false);
            LocationSimulator.isLocSimulatorOpen = intent.getBooleanExtra("simulate_location", false);
            LocationRecorder.get().initRecord(booleanExtra2, booleanExtra);
            if (!booleanExtra) {
                Workout workout = null;
                long longExtra = intent.getLongExtra("workout_id", 0L);
                if (longExtra > 0) {
                    workout = WorkoutDatabaseHelper.queryWorkoutById(longExtra);
                }
                dataTypes = intent.getIntArrayExtra("sport_data_types");
                startSport(dataTypes, workout);
            } else {
                Log.loge(TAG, "onStartCommand, daemon!!!");
                try {
                    Workout queryLastExceptionWorkout =
                            WorkoutDatabaseHelper.queryLastExceptionWorkout(SharedManager.getInstance().getUserId());
                    if (queryLastExceptionWorkout != null) {
                        if (XZDeviceHelper.hasBoundedDevices()) {
                            openBLE();
                        }
                        startSport(dataTypes, queryLastExceptionWorkout);
                        sendBroadcast(new Intent(TAG));
                    } else {
                        stopSelf();
                    }
                } catch (Exception unused) {
                    stopSelf();
                }
            }
            return Service.START_STICKY;
        }
        return Service.START_STICKY;
    }

    @Override
    public void onDestroy() {
        Log.logd(TAG, "onDestroy ======= ");
        super.onDestroy();
        if (recordWorkoutProcessor != null) {
            recordWorkoutProcessor.release();
            recordWorkoutProcessor = null;
        }
        if (simpleWorkoutProcessor != null) {
            simpleWorkoutProcessor.release();
            simpleWorkoutProcessor = null;
        }
        if (biciSimpleWorkoutProcessor != null) {
            biciSimpleWorkoutProcessor.release();
            biciSimpleWorkoutProcessor = null;
        }
        RemoteSharedPreference.getInstance().unregisterSPChangedListener(spChangedListener);
        SourcePointManager.terminate();
        RemoteSharedPreference.terminate();
        DeviceContext.release();
        isServiceRunning = false;
    }

    private void startSport(int[] vDataTypes, Workout workout) {
        boolean isTrainingMode;
        boolean isIndoorBikeMode = false;
        boolean isCrossTrainerMode = false;
        boolean isBikeTrainerMode = false;
        boolean isRowerMode = false;
        Log.logv(TAG, "[WorkoutRemoteService] startSport, lastWorkout = " + workout);
        if (workout == null) {
            isTrainingMode = RemoteSharedPreference.getInstance().getInt(SPConstant.KEY_SPORT_TYPE,
                    Workout.TYPE_CYCLING) == Workout.TYPE_TRAINING;
        } else {
            isTrainingMode = workout.getSport() == Workout.TYPE_TRAINING;
            isIndoorBikeMode = workout.getSport() == Workout.TYPE_INDOOR_BIKE;
            isCrossTrainerMode = workout.getSport() == Workout.TYPE_CROSS_TRAINER;
            isBikeTrainerMode = workout.getSport() == Workout.TYPE_BIKE_TRAINER;
            isRowerMode = workout.getSport() == Workout.TYPE_ROWER;
        }
        if (!isTrainingMode && !openGps()) {
            if (isIndoorBikeMode || isCrossTrainerMode || isBikeTrainerMode || isRowerMode) {
                //do nothing
            } else {
                stopSport();
            }
            return;
        }

        SourcePointManager.getInstance().openStepSensor(workout == null ? 0 : workout.getStep());
        isSporting = true;
        acquireWakeLock();
        showNotification();
        recordWorkoutProcessor = ProcessorFactory.create(ProcessorFactory.TYPE_RECORD);
        recordWorkoutProcessor.init(vDataTypes, workout);
        startTrackEngine();
        startDaemon();
    }

    private void stopSport() {
        Log.logv(TAG, "[WorkoutRemoteService] stopSport <<<< isSporting = " + isSporting);
        if (!isSporting) {
            return;
        }
        dumpLog();
        Log.logv(TAG, "[WorkoutRemoteService] closeGps");
        SourcePointManager.getInstance().closeSystemGps();
        SourcePointManager.getInstance().closeStepSensor();
        if (workoutTimer != null) {
            workoutTimer.cancel();
            workoutTimer.purge();
            workoutTimer = null;
        }
        if (recordWorkoutProcessor != null) {
            recordWorkoutProcessor.release();
            recordWorkoutProcessor = null;
        }
        stopForeground(true);
        ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).cancel(R.id.notification_remote_workout);
        Log.d(Constants.TAG, "releaseWakeLock ============== ");
        if (wakeLock != null) {
            wakeLock.release();
            wakeLock = null;
        }
        SourcePointManager.getInstance().release();
        LocationRecorder.get().releaseRecord();
        stopDaemon();
        isSporting = false;
        Log.logv(TAG, "[WorkoutRemoteService] stopSport >>>>");
    }

    private void openBLE() {
        if (App.getContext().isAppForeground()) {
            Intent intent = new Intent(DeviceService.ACTION_OPEN_BLE);
            intent.setPackage(getPackageName());
            startService(intent);
        }
    }

    private boolean openGps() {
        boolean openSystemGps = SourcePointManager.getInstance().openSystemGps();
        Log.logv(TAG, "[WorkoutRemoteService] openGps: " + openSystemGps);
        return openSystemGps;
    }

    private void startTrackEngine() {
        if (workoutTimer == null) {
            workoutTimer = new Timer();
            workoutTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    Log.d(TAG, "processSourcePoint...");
                    Log.d(TAG, "processRecordData recordWorkoutProcessor=" + recordWorkoutProcessor);
                    if (recordWorkoutProcessor != null) {
                        displayPoint = recordWorkoutProcessor.process(SourcePointManager.getInstance().getSourcePoint());
                    } else {
                        displayPoint = null;
                    }
                    if (System.currentTimeMillis() - lastDaemonTime > 60000) {
                        lastDaemonTime = System.currentTimeMillis();
                        Intent intent = new Intent("android.intent.action.MAIN");
                        intent.addCategory("android.intent.category.LAUNCHER");
                        intent.setClass(getApplicationContext(), LaunchActivity.class);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                        startActivity(intent);
                    }
                }
            }, 0L, TIME_INTERVAL);
        }
        Log.i(TAG, "startTrackEngine");
        lastDaemonTime = System.currentTimeMillis();
    }

    private void showNotification() {
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);// b.m
        NotificationCompat.Builder builder =
                new NotificationCompat.Builder(getApplicationContext(), NotificationConstants.CHANNEL_ID_SPORT);
        builder.setSmallIcon(R.drawable.ic_notification)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)).setOngoing(true)
                /*.setUsesChronometer(true).setWhen(System.currentTimeMillis())*/.setContentTitle("蓝行运动服务")
                .setContentText("心有远方，身必能至").setTicker("蓝行骑行").setDefaults(-1).setAutoCancel(false).setLocalOnly(true)
                .setChannelId(NotificationConstants.CHANNEL_ID_SPORT).setPriority(1)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
        Intent intent = new Intent();
        intent.setClass(getApplicationContext(), SportActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        int requestCode = (int) System.currentTimeMillis();
        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
                requestCode, intent,
                Build.VERSION.SDK_INT >= 31 ? PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
                        : PendingIntent.FLAG_UPDATE_CURRENT
        );

        builder.setContentIntent(pendingIntent);

        NotificationChannel notificationChannel = new NotificationChannel(NotificationConstants.CHANNEL_ID_SPORT,
                "蓝行骑行", NotificationManager.IMPORTANCE_HIGH);
        notificationChannel.setDescription("蓝行骑行记录服务");
        notificationChannel.enableVibration(true);
        notificationManager.createNotificationChannel(notificationChannel);
        Notification build = builder.build();
        builder.setPublicVersion(build);
        startForeground(R.id.notification_remote_workout, build);
        notificationManager.notify(R.id.notification_remote_workout, build);
    }

    private void acquireWakeLock() {
        Log.d(Constants.TAG, "acquireWakeLock ============== ");
        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        if (powerManager != null) {
            if (wakeLock == null) {
                wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "tag:lanxing");
                if (wakeLock == null) {
                    return;
                }
            }
            if (!wakeLock.isHeld()) {
                wakeLock.acquire();
                wakeLock.isHeld();
            }
        }
    }

    private void startDaemon() {
        JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        JobInfo.Builder builder =
                new JobInfo.Builder(1, new ComponentName(getApplicationContext(), DaemonService.class));
        builder.setPeriodic(30000L);
        try {
            daemonJobId = jobScheduler.schedule(builder.build());
            if (daemonJobId != 0) {
                return;
            }
            Log.logw("daemon", "start job service failed.");
            return;
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }

    private void stopDaemon() {
        JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        if (jobScheduler == null) {
            return;
        }
        if (daemonJobId > 0) {
            jobScheduler.cancel(daemonJobId);
            return;
        }
        for (JobInfo jobInfo : jobScheduler.getAllPendingJobs()) {
            if (jobInfo.getService().getClassName().equals(DaemonService.class.getName())) {
                jobScheduler.cancel(jobInfo.getId());
            }
        }
        return;
    }

    private void dumpLog() {
        if (!SharedManager.getInstance().getBoolean(SharedManager.KEY_DUMP_LOG_AFTER_STOP_SPORT, false)) {
            return;
        }
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm", Locale.getDefault());
            String buildExternalDirectoryPath = AppFileUtils.buildExternalDirectoryPath("log");
            File file = new File(buildExternalDirectoryPath, simpleDateFormat.format(System.currentTimeMillis()) + ".txt");
            Runtime runtime = Runtime.getRuntime();
            runtime.exec("logcat -f " + file.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}